//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<XAppFrame.cpp>
///	@path	~/src/appear/xwin/
///	@date	2008/10/11
///	@desc	.

#define _FULLAPI
#include "config/config.h"

#include "lib/utilities/observer.h"

#include "graphics/IRenderer.h"

#include "gui/style/style.h"
#include "gui/composite/composition.h"
#include "gui/composite/CCompositeTexture.h"
#include "gui/xgui/XDesktop.h"

#include "appear/xwin/IGuiEffect.h"
#include "appear/xwin/XAppFrame.h"
#include "appear/xwin/XAppDesktop.h"

namespace xeres {
	
	IMPL_IOBJECT_CLASS_DYNAMIC( XAppFrame );

	// XAppFrame
	XAppFrame::XAppFrame( void )
		: XFrame()
		, m_lastUpdate(0)
	{
		m_texture = new CCompositeTexture;
	}
	// XAppFrame
	XAppFrame::XAppFrame( const Rect<int>& placement )
		: XFrame( placement )
		, m_lastUpdate(0)
	{
		m_texture = new CCompositeTexture;
	}
	// XAppFrame
	XAppFrame::XAppFrame( const Pair<int>& size )
		: XFrame( size )
		, m_lastUpdate(0)
	{
		m_texture = new CCompositeTexture;
	}
	// ~XAppFrame
	XAppFrame::~XAppFrame( void )
	{
		m_texture = NULL;
	}
	// SetParent
	bool XAppFrame::SetParent( RefWeak<IGuiForm> parent )
	{
		if( !parent->IsA<XAppDesktop>() )
		{
			TRACE_ERROR( _S("XFrame::SetParent: XFrame can only be a child of XDesktop, failed to set '%s' as parent.") ,
				parent->GetClassName().c_str() );
			return false;
		}
		return __super::SetParent( parent );
	}
	// OnClose
	void XAppFrame::OnClose( void )
	{
		__super::OnClose();
		if( m_effect.IsValid() )
		{
			m_effect->Reset();
			m_effect = NULL;
			m_afterEffect = NULL;
		}
	}
	// IsTickable
	bool XAppFrame::IsTickable( void )
	{
		return __super::IsTickable() || m_effect.IsValid();
	}
	// Tick
	void XAppFrame::Tick( Updater& updater , float dTime )
	{
		__super::Tick( updater , dTime );
		if( m_effect.IsValid() )
		{
			if( !m_effect->Tick( dTime ) )
			{
				m_effect->Reset();
				m_effect->SetComp( NULL );
				m_effect = NULL;
				if( m_afterEffect )
				{
					m_afterEffect();
				}
				m_afterEffect = NULL;
				if( !IsTickable() )
					GetParent()->DelTickable( this );
			}
		}
	}
	// Draw
	void XAppFrame::Draw( RenderContext& rc , FrameComposition& fc )
	{
		if( NeedUpdate() && (Time::Now() - m_lastUpdate).ToMilliSecond() > 15  )
		{
			COUNTER_GUARD( _S("update") );

			RefWeak<IRenderer> renderer = rc.GetRenderer();

			Rect<int> region( m_updateRect );
			if( !m_texture->IsAttached() || m_texture->GetSize() != GetSize() )
			{
				m_texture->Reset( renderer , GetSize() , false );
				region = Rect<int>( 0 , 0 , GetSize() );
			}
			Composition composition( &m_texture->GetLayer() );
			m_texture->GetLayer().Clear( region.left() , region.top() , region.width() , region.height() );
			XS_VERIFY( composition.BeginPaint( region ) );
			composition.graphics().SetClip( toRect( region ) , Gdiplus::CombineModeIntersect );
			{
				__super::Draw( composition );
			}
			composition.EndPaint();

			// update content to texture.
			m_texture->Update( region );

			// Validate.
			ValidateUpdate();
			m_lastUpdate = Time::Now();
		}

		// Then composite to desktop.
		OnComposite( rc , fc );
	}
	// AttachEffect
	bool XAppFrame::AttachEffect( RefWeak<IGuiEffect> effect , function<void()> affterEffect )
	{
		if( m_effect.IsValid() && effect.IsValid() )
		{
			TRACE_ERROR( _S("XFrame::AttachEffect: Only one effect can be attached at one time.") );
			return false;
		}
		m_effect = effect;
		m_afterEffect = affterEffect;
		RefWeak<IGuiForm> parent = GetParent();
		if( parent.IsValid() )
			parent->AddTickable( this );
		return true;
	}
	// GetEffect
	RefWeak<IGuiEffect> XAppFrame::GetEffect( void )
	{
		return m_effect;
	}
	// OnComposite
	void XAppFrame::OnComposite( RenderContext& rc , FrameComposition& fc )
	{
		if( m_effect.IsValid() )
		{
			fc.DrawFrame( rc , GetPlacement() , m_texture , m_effect );
		}
		else
		{
			if( m_areoEdge.x < 0 || m_areoEdge.y < 0 )
			{
				fc.DrawFrame( rc , GetPlacement() , m_texture , NULL );
			}
			else
			{
				Rect<int> aero = GetPlacement();
				aero.extend( -m_areoEdge );
				fc.AeroCompositeFrame( rc , GetPlacement() , m_texture , aero );
			}
		}
	}

	// SetFrameEdge
	void XAppFrame::SetFrameEdge( const Pair<int>& edge )
	{
		if( edge.x < 0 || edge.y < 0 )
			m_areoEdge.set( -1 , -1 );
		else
			m_areoEdge = edge;
	}

	// GetFrameEdge
	const Pair<int>& XAppFrame::GetFrameEdge( void )
	{
		return m_areoEdge;
	}

} // namespace xeres
